package main.model.persistence;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Stack;
import main.model.Attribute;
import main.model.Cardinality;
import main.model.Diagram;
import main.model.Entity;
import main.model.Relation;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class DiagramHandler extends DefaultHandler {

	static private String DIAGRAM = "diagrama";
	static private String ENTITIES = "entidades";
	static private String RELATIONS = "relaciones";
	static private String ENTITY = "entidad";
	static private String RELATION = "relacion";
	static private String NAME = "nombre";
	static private String ATTRIBUTES = "atributos";
	static private String ATTRIBUTE = "atributo";
	static private String CARDINALITIES = "cardinalidades";
	static private String CARDINALITY = "cardinalidad";
	static private String MAX = "maxima";
	static private String MIN = "minima";
	static private String RELATED_ENTITIES = "entidadesRelacionadas";

	Diagram diagram = null;
	ArrayList<Entity> entities = null;
	ArrayList<Relation> relations = null;
	Entity tempEntity = null;
	Relation tempRelation = null;
	Cardinality tempCardinality = null;
	String value = "";

	Stack<Attribute> attributeStack = null;
	Stack<ArrayList<Attribute>> attributesList = null;

	boolean inDiagram = false;
	boolean inRelations = false;
	boolean inRelation = false;
	boolean inEntities = false;
	boolean inEntity = false;
	boolean inName = false;
	boolean inMax = false;
	boolean inMin = false;
	boolean inAttributes = false;
	boolean inAttribute = false;
	boolean inCardinalities = false;
	boolean inCardinality = false;
	boolean inRelatedEntities = false;
	int level = 0;

	public DiagramHandler() {
		diagram = new Diagram(null);
		attributeStack = new Stack<Attribute>();
		attributesList = new Stack<ArrayList<Attribute>>();
	}

	public Diagram getDiagram() {

		return diagram;
	}

	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		if (qName.equalsIgnoreCase(ENTITIES)) {
			inEntities = true;
			entities = new ArrayList<Entity>();
		}

		if (qName.equalsIgnoreCase(CARDINALITIES)) {
			inCardinalities = true;
		}

		if (qName.equalsIgnoreCase(CARDINALITY)) {
			inCardinality = true;
			tempCardinality = new Cardinality();
		}

		if (qName.equalsIgnoreCase(MAX)) {
			inMax = true;
		}

		if (qName.equalsIgnoreCase(MIN)) {
			inMin = true;
		}

		if (qName.equalsIgnoreCase(RELATIONS)) {
			inRelations = true;
			relations = new ArrayList<Relation>();
		}

		if (qName.equalsIgnoreCase(RELATION)) {
			inRelation = true;
			tempRelation = new Relation();
		}

		if (qName.equalsIgnoreCase(ENTITY)) {
			inEntity = true;
			if (!inRelatedEntities) {
				tempEntity = new Entity();
			}
		}

		if (qName.equalsIgnoreCase(RELATION)) {
			inRelation = true;
			tempRelation = new Relation();
		}

		if (qName.equalsIgnoreCase(ATTRIBUTES)) {
			inAttributes = true;
			level++;
			ArrayList<Attribute> tempattList = new ArrayList<Attribute>();
			if(!attributeStack.empty()){
				attributeStack.peek().setAttributes(tempattList);
			}else{
				if(inEntity){
					tempEntity.setAttributes(tempattList);
				}else if (inRelation){
					tempRelation.setAttributes(tempattList);
				}
			}
			attributesList.push(tempattList);
		}

		if (qName.equalsIgnoreCase(ATTRIBUTE)) {
			inAttribute = true;
			if (!inCardinality) {
				attributeStack.push(new Attribute());
			}
		}

		if (qName.equalsIgnoreCase(NAME)) {
			inName = true;
		}

		if (qName.equalsIgnoreCase(RELATED_ENTITIES)) {
			inRelatedEntities = true;
		}

		if (qName.equalsIgnoreCase(DIAGRAM)) {
			inDiagram = true;
		}
	}

	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		value = value.replace('\t', ' ');
		value = value.replace('\n', ' ');
		value = value.trim();
		if (qName.equalsIgnoreCase(ENTITIES)) {
			inEntities = false;
			diagram.setEntities(entities);
		}

		if (qName.equalsIgnoreCase(RELATIONS)) {
			inRelations = false;
			diagram.setRelations(relations);
		}

		if (qName.equalsIgnoreCase(RELATION)) {
			inRelation = false;
			if(!attributesList.empty()){
				tempRelation.setAttributes(attributesList.pop());
			}
			relations.add(tempRelation);
		}
		
		
		if (qName.equalsIgnoreCase(ENTITY)) {
			inEntity = false;
			if (!inRelatedEntities) {
				if(!attributesList.empty()){
					tempEntity.setAttributes(attributesList.pop());
				}
				entities.add(tempEntity);
			} else {
				tempRelation.addEntity(tempEntity);
				tempRelation
						.setCardinalityToEntity(tempEntity, tempCardinality);
			}
		}

		if (qName.equalsIgnoreCase(ATTRIBUTES)) {
			level--;
			inAttributes = !attributesList.empty();
		}

		if (qName.equalsIgnoreCase(ATTRIBUTE)) {
			if (!inCardinality) {
				if(attributeStack.peek().getAttributes()== attributesList.peek()){
					attributesList.pop();
				}
				attributesList.peek().add(attributeStack.pop());
			} else {
				if(inAttribute && level>0){
					Attribute tempAttribute = attributeStack.peek().getAttribute(value);
					tempAttribute.setCardinality(tempCardinality);
				}else if (inEntity) {
					Attribute tempAttribute = tempEntity.getAttribute(value);
					tempAttribute.setCardinality(tempCardinality);
				}else if(inRelation){
					Attribute tempAttribute = tempRelation.getAttribute(value);
					tempAttribute.setCardinality(tempCardinality);
				}
			}
			value = "";
			inAttribute = !attributeStack.empty();
		}

		if (qName.equalsIgnoreCase(CARDINALITIES)) {
			inCardinalities = false;
		}

		if (qName.equalsIgnoreCase(CARDINALITY)) {
			inCardinality = false;
		}

		if (qName.equalsIgnoreCase(MAX)) {
			inMax = false;
			tempCardinality.setMax(value);
			value = "";
		}

		if (qName.equalsIgnoreCase(MIN)) {
			inMin = false;
			tempCardinality.setMin(value);
			value = "";
		}

		if (qName.equalsIgnoreCase(NAME)) {
			inName = false;
			if (inAttribute) {
				attributeStack.peek().setName(value);
			} else if (inEntity) {
				if (inRelatedEntities) {
					tempEntity = getEntity(value);
				} else {
					tempEntity.setName(value);
				}
			} else if (inRelation) {
				tempRelation.setName(value);
			} else if (inDiagram) {
				diagram.setName(value);
			}
			System.out.println(value);
			value = "";
		}

		if (qName.equalsIgnoreCase(RELATED_ENTITIES)) {
			inRelatedEntities = false;
		}

		if (qName.equalsIgnoreCase(DIAGRAM)) {
			inDiagram = false;
		}
	}

	public void characters(char ch[], int start, int length)
			throws SAXException {
		if (inName || inAttribute || inMax || inMin) {
			value = value.concat(new String(ch, start, length));
		}
	}

	private Entity getEntity(String entity_name) {
		Iterator<Entity> itr = entities.iterator();
		Entity ent_result = null;
		while (itr.hasNext()) {
			Entity element = itr.next();
			if (element.getName().compareTo(entity_name) == 0) {
				ent_result = element;
			}
		}
		return ent_result;
	}

}
